<template>
    <div class="dataset-list-wrapper">
        <div class="dataset-list-header">
            <div>
                <el-tag class="tool-tag" type="info" effect="plain" size="large" @click="onClickMachine"># {{ _machine
                    }}</el-tag>
                <el-button class="tool-btn" type="danger" plain @click="importDataset('image')">导入图像</el-button>
                <el-button class="tool-btn" type="danger" plain @click="importDataset('video')">导入视频</el-button>
            </div>
            <el-input class="search-box" placeholder="搜索数据集" suffix-icon="Search" round></el-input>
        </div>
        <div class="dataset-list">
            <el-table size="small" :data="_dataset_list" highlight-current-row table-layout="fixed">
                <el-table-column prop="id" label="标识" width="110"> </el-table-column>
                <el-table-column prop="dataset_name" label="数据集名称" min-width="120"> </el-table-column>
                <el-table-column prop="dataset_dir" label="数据集目录" min-width="180"> </el-table-column>
                <el-table-column prop="label_format" label="标注格式" width="80"> </el-table-column>
                <el-table-column prop="total_samples" label="样本总量" width="80"> </el-table-column>
                <el-table-column prop="labeled_samples" label="已标注量" width="80"> </el-table-column>
                <el-table-column prop="update_time" label="更新时间" min-width="140"> </el-table-column>
                <el-table-column fixed="right" label="操作" width="130">
                    <template #default="scope">
                        <div v-if="scope.row.status === 'idle'">
                            <el-tooltip content="查看" placement="bottom" effect="light">
                                <el-button link type="primary" size="small" style="margin-left: 5px"
                                    @click.prevent="handleView(scope.$index, scope.row)">
                                    <View class="operation-icon" />
                                </el-button>
                            </el-tooltip>
                            <el-tooltip content="标注" placement="bottom" effect="light">
                                <el-button link type="primary" size="small"
                                    @click.prevent="handleLabel(scope.$index, scope.row)">
                                    <Edit class="operation-icon" />
                                </el-button>
                            </el-tooltip>
                            <el-tooltip content="更多" placement="bottom" effect="light">
                                <el-dropdown trigger="click">
                                    <el-button link type="primary" size="small">
                                        <More class="operation-icon" />
                                    </el-button>
                                    <template #dropdown>
                                        <el-dropdown-menu>
                                            <el-dropdown-item :icon="DataLine"
                                                @click="handlePipeline(scope.$index, scope.row)"> 推理 </el-dropdown-item>
                                            <el-dropdown-item :icon="DocumentAdd"
                                                @click="handleImport(scope.$index, scope.row)"> 导入 </el-dropdown-item>
                                            <el-dropdown-item :icon="Download"
                                                @click="handleExport(scope.$index, scope.row)"> 导出 </el-dropdown-item>
                                            <el-dropdown-item :icon="Setting"
                                                @click="handleSetting(scope.$index, scope.row)"> 设置 </el-dropdown-item>
                                            <el-dropdown-item :icon="Delete"
                                                @click="handleDelete(scope.$index, scope.row)">
                                                删除 </el-dropdown-item>
                                        </el-dropdown-menu>
                                    </template>
                                </el-dropdown>
                            </el-tooltip>
                        </div>
                        <div v-if="scope.row.status !== 'idle'">
                            标注中: {{ scope.row.percent }}%
                        </div>
                    </template>
                </el-table-column>
            </el-table>
        </div>
    </div>
    <!-- 打开目录对话框 -->
    <OpenDirectory :openDirectoryVisible="openDirectoryVisible" @directory-confirm="onDirectoryConfirm"></OpenDirectory>
    <!-- 设置数据集对话框 -->
    <DatasetSetting :openSettingVisible="openSettingVisible" :datasetInfo="datasetInfo"
        @setting-confirm="onSettingConfirm">
    </DatasetSetting>
    <!-- pipeline列表对话框 -->
    <PipeDlg ref="pipelineDialog" @dlg-confirm="onPipelineInput"></PipeDlg>
</template>

<script setup>
import { reactive, ref, onMounted, toRaw, inject } from 'vue';
import { Download, Delete, DocumentAdd, Setting, DataLine } from '@element-plus/icons-vue';
import OpenDirectory from './OpenDirectory.vue';
import DatasetSetting from './DatasetSetting.vue';
import PipeDlg from '../PipelinePages/PipeDlg.vue';
import API from '@/js/api';
import { generateTimestampBasedID } from '@/js/utils/baseUtils';

let vueApp = inject('vueApp');
const emit = defineEmits(['loadDataset']);

let _machine = ref('Local');
let _dataset_type = ref('detection');
let _dataset_list = ref([]);

// 显示创建数据集的对话框
let openDirectoryVisible = ref(false);
let form = reactive({
    dataset_dir: '',
    label_format: 'voc',
    label_selections: []
});
let _importType = 'image';

// 加载数据集过程中的提示文字
let loading = null;

// 调用pipeline对话框
const pipelineDialog = ref(null);

function importDataset(type) {
    _importType = type;
    openDirectoryVisible.value = true;
}
function onDirectoryConfirm(confirmInfo) {
    // console.log('onDirectoryConfirm confirmInfo = ', confirmInfo);
    openDirectoryVisible.value = false;
    if (confirmInfo) {
        form.dataset_dir = confirmInfo.dataset_dir;
        form.label_format = confirmInfo.label_format;
        form.label_selections = confirmInfo.label_selections;

        if (_importType == 'image') {
            // 如果选择图片类型，则直接创建数据集
            createDataset();
        } else if (_importType == 'video') {
            // 如果选择视频类型，则先抽帧后在创建数据集
            extractVideos();
        }
    }
}

// 显示打开配置对话框
let openSettingVisible = ref(false);
let datasetInfo = ref(null);
function onOpenSetting() {
    openSettingVisible.value = true;
}
function onSettingConfirm() {
    openSettingVisible.value = false;
}

async function extractVideos() {
    try {
        // 建立异步回调函数
        const taskId = `extract_videos:${generateTimestampBasedID()}`;
        await API.stopAsyncPolling();
        API.asyncTaskPolling(taskId, onExtractVideosCallback, 200, null, true);

        // 调用接口，抽取视频帧
        let result = await API.invoke('ExtractFrames', {
            taskId: taskId,
            dir: form.dataset_dir,
            fps: 1,
            quality: 2
        });

        console.log('extractVideos ret = ', result);
        if (result.code !== 0) {
            ElMessage.error('视频抽帧失败，错误：' + result.msg);
            await API.stopAsyncPolling();
        } else {
            if (!loading) {
                loading = ElLoading.service({
                    lock: true,
                    text: '开始抽取视频帧',
                    background: 'rgba(0, 0, 0, 0.7)'
                });
            }
        }
    } catch (error) { }
}

async function onExtractVideosCallback(task_id, message) {
    // console.log(`onExtractVideosCallback task_id = ${task_id}, message = `, message);
    if (message.event === 'process-complete' || message.event === 'frame-progress') {
        loading.setText(message.data);
    } else if (message.event === 'extract-complete') {
        loading && loading.close();
        loading = null;
        createDataset();
    }
}

async function createDataset() {
    try {
        // 获取算法类别
        let algo_type = vueApp.getAlgoType();

        // 建立异步回调函数
        const datasetId = generateTimestampBasedID();
        await API.stopAsyncPolling();
        API.asyncTaskPolling(`dataset_parse:${datasetId}`, onCreateDatasetCallback, 200, null, true);

        // 创建数据集
        let result = await API.invoke('CreateDataset', {
            id: datasetId,
            dataset_supertype: algo_type.supertype,
            dataset_type: algo_type.type,
            dataset_dir: form.dataset_dir,
            label_format: form.label_format,
            label_selections: JSON.stringify(form.label_selections)
        });

        // 判断返回值是否成功
        console.log('createDataset ret = ', result);
        if (result.code !== 0) {
            ElMessage.error('数据集创建失败！，错误：' + result.msg);
            await API.stopAsyncPolling();
        } else {
            if (!loading) {
                loading = ElLoading.service({
                    lock: true,
                    text: '加载中...',
                    background: 'rgba(0, 0, 0, 0.7)'
                });
            }
        }
    } catch (error) { }
}

async function onCreateDatasetCallback(task_id, message) {
    // console.log(`onCreateDatasetCallback task_id = ${task_id}, message = `, message);
    if (message.event === 'parse_status') {
        loading.setText(message.data);
    } else if (message.event === 'parse_percent') {
        loading.setText(`读取进度： ${message.data}%`);
    } else if (message.event === 'parse_end') {
        ElMessage.success('数据集创建成功!');
        loading && loading.close();
        loading = null;
        getDatasetList();
    }
}

async function getDatasetList() {
    // 显示加载中，并调用本地服务
    try {
        const loading = ElLoading.service({
            lock: true,
            text: '加载中...',
            background: 'rgba(0, 0, 0, 0.7)'
        });

        // 读取本地数据集接口
        let algo_type = vueApp.getAlgoType();
        // console.log('algo_type = ', algo_type);
        let result = await API.invoke('GetDatasetList', {
            dataset_supertype: algo_type.supertype,
            dataset_type: algo_type.type
        });
        loading.close();

        // console.log(result.msg);
        if (result && result.code == 0) {
            _machine.value = API.getProvider();
            _dataset_list.value = result.msg;
        }
    } catch (error) {
        console.error(error);
    }
}

function setDatasetType(type_info) {
    // console.log('setDatasetType type_info = ', type_info);
    _dataset_type.value = type_info.dataset_type;
    if (type_info.data_src == 'local') {
        getDatasetList();
    } else {
        _dataset_list.value = [];
    }
}

async function checkDatasetDirectory(dataset_info) {
    let result = await API.invoke('IsDirectoryExists', {
        directory: dataset_info.dataset_dir
    });

    if (!result.msg) {
        try {
            await ElMessageBox.confirm(`${dataset_info.dataset_name}根目录不存在，是否更新根目录？`, 'Warning', {
                confirmButtonText: '更新',
                cancelButtonText: '取消',
                type: 'warning'
            });
            let result = await API.invoke('OpenDirectory');
            let dataset_dir = result.msg;
            if (dataset_dir) {
                dataset_info.dataset_dir = dataset_dir;
                result = await API.invoke('UpdateDataset', dataset_info);
                if (result.code == 0) {
                    ElMessage.success('数据集目录更新成功！');
                    getDatasetList();
                } else {
                    ElMessage.error('数据集目录更新失败！，错误：' + result.msg);
                }
            }
        } catch (error) { }
    }
}

async function handleView(index, row) {
    // console.log(`handleView index = ${index}, row = `, row);
    let dataset_info = toRaw(row);
    await checkDatasetDirectory(dataset_info);
    emit('loadDataset', { panel: 'grid_panel', dataset_id: row.id });
}

async function handleLabel(index, row) {
    // console.log(`handleLabel index = ${index}, row = `, row);
    let dataset_info = toRaw(row);
    await checkDatasetDirectory(dataset_info);
    emit('loadDataset', { panel: 'tool_panel', dataset_id: row.id });
}

async function handlePipeline(index, row) {
    // console.log('handlePipeline index = ', index, ', row = ', row);
    pipelineDialog.value.showDialog({
        invoke_from: 'dataset',
        batch: true,
        input_data: {
            image: `dataset://${_machine.value}/${row.id}`
        }
    });
}

async function onPipelineInput(inputs) {
    // console.log('onPipelineInput inputs = ', inputs);
    const jobId = generateTimestampBasedID();
    await API.stopAsyncPolling();
    API.asyncTaskPolling(`pipeline:${jobId}`, onPipelineOutput, 500, null, true);

    // 调用pipeline
    let result = await API.invoke('PipelineStart', {
        ...inputs,
        jobId: jobId
    });
    console.log(result);
}

async function onPipelineOutput(jobId, message) {
    console.log(`onPipelineOutput jobId = ${jobId}, message = `, message);
    if (message.event === 'pipeline_percent') {
        let dataset = _dataset_list.value.find((item) => item.id === message.data.datasetId);
        dataset.status = 'processing';
        dataset.percent = message.data.percent;
    } else if (message.event === 'pipeline_result') {
        getDatasetList();
        ElMessage.success('推理完成！');
    } else if (message.event === 'pipeline_error') {
        ElMessage.error('推理失败！，错误：' + message.data);
    }
}

async function handleImport(index, row) {
    console.log(`handleImport index = ${index}, row = `, row);
}

async function handleExport(index, row) {
    console.log(`handleExport index = ${index}, row = `, row);
}

async function handleSetting(index, row) {
    // console.log(`handleSetting index = ${index}, row = `, row);
    datasetInfo.value = row;
    onOpenSetting();
}

async function handleDelete(index, row) {
    // console.log(`handleDelete index = ${index}, row = `, row);
    let dataset_info = toRaw(row);
    let result = await API.invoke('DeleteDataset', { dataset_id: dataset_info.id });
    console.log(result);
    if (result.code == 0) {
        ElMessage.success('数据集删除成功！');
        getDatasetList();
    } else {
        ElMessage.error('数据集删除失败！，错误：' + result.msg);
    }
}

function onClickMachine() { }

onMounted(() => {
    getDatasetList();
});

defineExpose({ setDatasetType, getDatasetList });
</script>

<style scoped>
.dataset-list-wrapper {
    background-color: rgb(255, 255, 255);
    width: calc(100% - 250px);
    height: 100%;
    padding: 0px;
}

.dataset-list-wrapper .dataset-list-header {
    display: flex;
    background-color: rgb(249, 248, 248);
    justify-content: space-between;
    align-items: center;
    padding: 10px;
}

.search-box {
    margin-left: 16px;
    width: 150px;
    border-radius: 10px;
}

.dataset-list {
    width: 100%;
    height: calc(100% - 54px);
    padding: 5px;
}

.el-table {
    width: 100%;
    height: 100%;
}

.el-button {
    margin-left: 2px;
    margin-right: 10px;
}

.operation-icon {
    padding: 2px 2px 0px 0;
    width: 1.4em;
    height: 1.4em;
    color: rgb(18, 18, 227);
    font-weight: 700;
}

.tool-tag {
    margin: 0px 10px 0px 0px;
    cursor: default;
}
</style>
